/*************************************************************************
 *************************************************************************
 	 	 	 	 	 	 	M2SMA : Scheduler.h
 *************************************************************************
 *
 	 Copyright (C) 2008
 	 Steven Costiou, Julien Yven; Master 2 Complex Systems
 	 University of Western Brittany (UBO), Brest, France
 *
 *************************************************************************
 *************************************************************************
 *
 	 Copyright (C) 2011
 	 M2SMA reworked and simplified core, Steven Costiou, France
 *
 **************************************************************************
 **************************************************************************
 *
 	 The scheduler does manage every agent created in the system.

	 Its purpose is to perform cycles, one cycle being a call to every
	 agent's method "live()". It calls each agent following specifics
	 policies (like sequential or random calls).

 	 Agents are then allowed to live - through their method live() -
 	 meaning to perform their work in the system.

 	 The scheduler also stores many informations on created agents, like
	 agent counters (absolute and by class of agent), lists of agents by
	 classes, direct pointers on to these agents, etc..
 *
 **************************************************************************
 **************************************************************************
 *
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/
 *
 **************************************************************************
 **************************************************************************/

using namespace std;

#ifndef SCHEDULER_H
#define SCHEDULER_H

#include <string>
#include <vector>
#include <set>
#include "Agent.h"
#include "M2SMA_EXCEPTIONS.h"
#include "CORE_TYPES_AND_DEFINITIONS.h"

#include "COMMON_LIBS.h"

class Scheduler
{
    public:

        Scheduler();
        virtual ~Scheduler();

        void setMode(int aMode) { this->schedulingMode = aMode; };
        int getMode() { return this->schedulingMode; };
        map<string, Agent*>* getAgentList() { return this->agentList; };
        map<string, int>* getAgentClassesList() { return this-> agentClassesList; };
        vector<Agent*>* getAgentsToSchedule() { return this->toScheduleAgents; };
        set<Agent*>* getAgentPtrs() { return this->agentPtrs; };
        map<string, set<Agent*> >* getAgentListByClasses() { return this->agentListByClasses; };

        /**
         * Initializes a new agent and adds it to the agent lists.
         */
        void newAgent(Agent* anAgent);

        /**
         * Adds an agent to the agent lists.
         */
        void addAgent(Agent* anAgent);

        /**
         *  Remove an agent from all data structures, must be called by an Agent.
         */
        virtual void removeAndClearAgent(Agent* anAgent);

        /**
         * Does a scheduling cycle, according to the current scheduling mode.
         */
        virtual void cycle();

    protected:

        void increaseAgentCounter() { this->agentCounter++; };
        void decreaseAgentCounter() { this->agentCounter--; };
        int getAgentCounter() {return this->agentCounter; };

        void addAgentPointer(Agent* anAgentPointer);
        void eraseAllAgents();

    private:

        Scheduler(const Scheduler& aScheduler);
        void initializeAttributes();
        string intToString(int i);

        /**
         * Builds a name for an agent using its class name and the agentNumber list.
         */
        string buildName(string agentClassName);
        void increaseNumberOfCreatedAgentOfClass(string anAgentClassName);
        int getNumberOfCreatedAgentOfClass(string anAgentClassName);
        void addNewAgentToClassOrderedLists(Agent* anAgent);

        void performSequentialScheduling();
        void performRandomScheduling();

    private:

        int agentCounter;
        int schedulingMode;

        map<string, Agent*>* agentList;
        vector<Agent*>* toScheduleAgents;
        set<Agent*>* agentPtrs;

        /**
         * Absolute Agent counters, ordered by classes - used to give unique names to agents.
         * Counters are maintained to their values even if an agent of some class is deleted.
         * Counters are however updated if any agent of any class is added to the system.
         */
        map<string, int>* agentClassesList;

        /**
         * List of every existing agent ordered by classes
         * Unlike the absolute agent counters list, agents are removed
         * from the list if they are not part of the system anymore.
         */
        map<string, set<Agent*> >* agentListByClasses;
};

#endif /** SCHEDULER_H **/
